package com.gzh.system.service.impl;


import com.gzh.core.dao.mapper.CourseMapper;
import com.gzh.core.dao.mapper.UserMapper;
import com.gzh.core.dao.mapper.WorkMapper;
import com.gzh.core.dao.po.CourseEntity;
import com.gzh.core.dao.po.UserEntity;
import com.gzh.core.dao.po.WorkEntity;
import com.gzh.core.util.StringUtils;
import com.gzh.core.util.constant.ErrorCode;
import com.gzh.core.util.exception.BusinessException;
import com.gzh.system.dao.po.QueryRemindUserEntity;
import com.gzh.system.service.MailService;
import com.gzh.system.service.RabbitMQService;
import com.gzh.system.service.dto.RemindInfo;
import com.sun.mail.util.MailSSLSocketFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Condition;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MailServiceImpl implements MailService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WorkMapper workMapper;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private RabbitMQService rabbitMQService;

    @Value("${config.mail.host}")
    private String host;

    @Value("${config.mail.username}")
    private String username;

    @Value("${config.mail.password}")
    private String password;

    public boolean sendMail(String mailTo) {
        Transport ts = null;
        try {
            Session session = getSession();
            ts = session.getTransport();
            // 连接邮件服务器：邮箱类型，帐号，POP3/SMTP协议授权码 163使用：smtp.163.com
            ts = getTransport(ts);
            // 创建邮件
            Message message = createSimpleMail(session, mailTo);
            // 发送邮件
            ts.sendMessage(message, message.getAllRecipients());
            return true;
        } catch (Exception e) {
            log.error("发送邮件失败", e);
            throw new BusinessException(ErrorCode.MAIL_001);
        } finally {
            if (ts != null) {
                try {
                    ts.close();
                } catch (MessagingException e) {
                    log.error("Transport关闭失败", e);
                }
            }
        }
    }

    public void sendXXLMail(List<QueryRemindUserEntity> list) {
        Transport ts = null;
        try {
            Session session = getSession();
            ts = session.getTransport();
            // 连接邮件服务器：邮箱类型，帐号，POP3/SMTP协议授权码 163使用：smtp.163.com
            ts = getTransport(ts);
            // 创建邮件
            Message message = createXXLMail(session, list);
            // 发送邮件
            ts.sendMessage(message, message.getAllRecipients());
        } catch (Exception e) {
            log.error("发送邮件失败", e);
        } finally {
            if (ts != null) {
                try {
                    ts.close();
                } catch (MessagingException e) {
                    log.error("Transport关闭失败", e);
                }
            }
        }
    }


    @Override
    public Session getSession() {
        Properties prop = new Properties();
        // 开启debug调试，以便在控制台查看
        prop.setProperty("mail.debug", "true");
        // 设置邮件服务器主机名
        prop.setProperty("mail.host", host);
        // 发送服务器需要身份验证
        prop.setProperty("mail.smtp.auth", "true");
        // 发送邮件协议名称
        prop.setProperty("mail.transport.protocol", "smtp");
        // 开启SSL加密，否则会失败
        MailSSLSocketFactory sf = null;
        try {
            sf = new MailSSLSocketFactory();
        } catch (GeneralSecurityException e) {
            log.error("开启SSL加密失败");
        }
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable", "true");
        prop.put("mail.smtp.ssl.socketFactory", sf);
        // 创建session
        Session session = Session.getInstance(prop);
        return session;
    }

    @Override
    public Transport getTransport(Transport ts){
        try {
            ts.connect(host, username, password);
        } catch (MessagingException e) {
            log.error("连接Transport失败");
        }
        return ts;
    }

    @Override
    public void remindMail(RemindInfo info) {
        List<Integer> userIdList = info.getUserId();
        Condition userCondition = new Condition(UserEntity.class);
        userCondition.createCriteria().andIn("userId",userIdList);
        List<UserEntity> userEntityList = userMapper.selectByCondition(userCondition);
        List<String> mailList = userEntityList.stream().map(t -> t.getMail()).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(userEntityList)){
            WorkEntity workEntityQuery = new WorkEntity();
            workEntityQuery.setWorkId(info.getWorkId());
            List<WorkEntity> workEntityList = workMapper.select(workEntityQuery);
            info.setWorkName(workEntityList.get(0).getWorkName());
            info.setEndDate(workEntityList.get(0).getEndDate());
            info.setEndTime(workEntityList.get(0).getEndTime());
            CourseEntity courseEntityQuery = new CourseEntity();
            courseEntityQuery.setCourseId(workEntityList.get(0).getCourseId());
            List<CourseEntity> courseEntityList = courseMapper.select(courseEntityQuery);
            info.setCourseName(courseEntityList.get(0).getCourseName());
            info.setCourseId(courseEntityList.get(0).getCourseId());
        }
        for (String mail : mailList) {
            info.setMail(mail);
            rabbitMQService.sendMsg(info);
        }
    }

    @Override
    public void checkMail(List<UserEntity> userEntityList,Integer checkId) {
        Transport ts = null;
        try {
            Session session = getSession();
            ts = session.getTransport();
            // 连接邮件服务器：邮箱类型，帐号，POP3/SMTP协议授权码 163使用：smtp.163.com
            ts = getTransport(ts);
            // 创建邮件
            Message message = createMail(session,userEntityList,checkId);
            // 发送邮件
            ts.sendMessage(message, message.getAllRecipients());
        } catch (Exception e) {
            log.error("发送邮件失败",e);
        }finally {
            if (ts != null) {
                try {
                    ts.close();
                } catch (MessagingException e) {
                    log.error("Transport关闭失败", e);
                }
            }
        }
    }

    private Message createMail(Session session, List<UserEntity> userEntityList,Integer checkId) throws Exception {
        // 创建邮件对象
        MimeMessage message = new MimeMessage(session);
        InternetAddress[] address = new InternetAddress[userEntityList.size()] ;
        for (int i = 0; i < userEntityList.size(); i++) {
            address[i] = new InternetAddress(userEntityList.get(i).getMail());
        }
        // 指明邮件的发件人
        message.setFrom(new InternetAddress(username));
        // 指明邮件的收件人，发件人和收件人如果是一样的，那就是自己给自己发
        message.setRecipients(Message.RecipientType.TO, address);
        // 邮件的标题
        message.setSubject("课程签到通知");
        StringBuffer sb = new StringBuffer();

        sb.append("请点击下方网址进行签到<br/>");
        sb.append("http://127.0.0.1:3000/#/courseCheckIn?checkId="+checkId+"<br/>");
        sb.append("http://guanhaha.icu/#/courseCheckIn?checkId="+checkId+"<br/>");
        // 邮件的文本内容
        message.setContent(sb.toString() + "请勿回复此邮箱", "text/html;charset=UTF-8");
        // 返回创建好的邮件对象
        return message;
    }


    public MimeMessage createSimpleMail(Session session, String mailTo) throws Exception {
        String verificationCode = StringUtils.getVerificationCode();
        //邮箱对应验证码
        redisTemplate.opsForValue().set(mailTo, verificationCode, Duration.ofMinutes(60));
        // 创建邮件对象
        MimeMessage message = new MimeMessage(session);
        // 指明邮件的发件人
        message.setFrom(new InternetAddress(username));
        // 指明邮件的收件人，发件人和收件人如果是一样的，那就是自己给自己发
        message.setRecipient(Message.RecipientType.TO, new InternetAddress(mailTo));
        // 邮件的标题
        message.setSubject("登录验证码");
        // 邮件的文本内容
        message.setContent("欢迎登陆,账号验证码为(三分钟有效):" + verificationCode + ",请勿回复此邮箱", "text/html;charset=UTF-8");
        // 返回创建好的邮件对象
        return message;
    }

    private Message createXXLMail(Session session, List<QueryRemindUserEntity> list) throws Exception{
        // 创建邮件对象
        MimeMessage message = new MimeMessage(session);
        // 指明邮件的发件人
        message.setFrom(new InternetAddress(username));
        // 指明邮件的收件人，发件人和收件人如果是一样的，那就是自己给自己发
        message.setRecipient(Message.RecipientType.TO, new InternetAddress(list.get(0).getMail()));
        // 邮件的标题
        message.setSubject("作业即将截至通知");
        StringBuffer sb = new StringBuffer();

        sb.append(list.get(0).getFullName() +"同学:<br/>");
        for (QueryRemindUserEntity entity : list) {
            sb.append("课程:" + entity.getCourseName() +
                    "<br/>作业:" +entity.getWorkName() + "<br/>"
                    + "将在" + StringUtils.formatTime(entity.getEndDate(),entity.getEndTime()) + "截止,请及时完成<br/><br/>");
        }
        // 邮件的文本内容
        message.setContent(sb.toString() + "请勿回复此邮箱", "text/html;charset=UTF-8");
        // 返回创建好的邮件对象
        return message;
    }
}
